# -*- coding:utf-8 -*-
import asyncio
import hashlib
import base64
import hmac
import time
import json
import ssl
import redis.asyncio as aioredis
from fastapi import APIRouter, Query, HTTPException, Header, BackgroundTasks
from typing import List
import websockets  # 替换 websocket 库为 websockets
from uuid import uuid4
from service.question_service import save_questions_to_db
from service.resumes_service import create_interview_record
from util.JWTutil import JWTUtil

# 初始化路由
router = APIRouter()

# 全局 Redis 连接实例（由 main.py 注入）
redis_client = None
redis_pubsub_pool = {}

def init_redis(client: aioredis.Redis):
    global redis_client
    redis_client = client

# 新增全局变量用于保存配置
config = {}

def init_config(app_config):
    """
    初始化配置，由 main.py 调用
    :param app_config: dict 类型，包含必要的配置项
    """
    global config
    config.update(app_config)

class Document_Q_And_A:
    def __init__(self, APPId, APISecret, TimeStamp, OriginUrl):
        self.appId = APPId
        self.apiSecret = APISecret
        self.timeStamp = TimeStamp
        self.originUrl = OriginUrl

    def get_origin_signature(self):
        m2 = hashlib.md5()
        data = bytes(self.appId + self.timeStamp, encoding="utf-8")
        m2.update(data)
        checkSum = m2.hexdigest()
        return checkSum

    def get_signature(self):
        signature_origin = self.get_origin_signature()
        signature = hmac.new(
            self.apiSecret.encode('utf-8'),
            signature_origin.encode('utf-8'),
            digestmod=hashlib.sha1
        ).digest()
        signature = base64.b64encode(signature).decode(encoding='utf-8')
        return signature

    def get_url(self):
        signature = self.get_signature()
        return f"{self.originUrl}?appId={self.appId}&timestamp={self.timeStamp}&signature={signature}"

    def get_body(self, file_ids: List[str], repo_id: str = None, job_position: str = None):
        job_desc = f"用户申请的【{job_position}】岗位" if job_position else "用户上传简历中申请的岗位"

        data = {
            "chatExtends": {
                 "wikiPromptTpl": f"""你是面试官，请根据已经上传的文件内容以及文件里面的项目，以及用户面试岗位{job_desc}，提出包含基础知识、技术深度、算法与数据结构、简历中项目的考察、软技能、场景模拟等方面的10个问题，score字段用于计算问题的难度及评分比重。
每个问题请以如下严格的JSON格式返回：
{{
  "id": 1,
  "context": "问题内容",
  "type": "问题类型，例如：技术能力、行为面试、项目追问",
  "score": 10,
  "test":"如果是代码题，标注为true，非代码题，标注为false"
}}
输出结果必须是纯JSON数组格式，且不要包含任何额外信息。""",
                "wikiFilterScore": 0.83,
                "temperature": 0.5
            },
            "fileIds": file_ids,
            "messages": [
                {
                    "role": "user",
                    "content": "根据简历提出问题"
                }
            ]
        }

        if repo_id:
            data["repoId"] = repo_id

        return data


import json
from typing import List, Tuple

class IncompleteJSONError(Exception):
    """自定义异常，表示缓冲区内容不完整"""
    pass

async def send_websocket_request(ws_url: str, body: dict, interview_id: str, websocket_connection=None):
    buffer = '' #缓存区存储
    parsed_objects = []  # ✅ 新增变量存储解析结果

    async def process_buffer():
        nonlocal buffer
        if '}' not in buffer:
            return  # 无完整JSON结构直接返回

        try:
            # 找到最后一个右括号位置
            end_pos = buffer.rfind('}')
            if end_pos == -1:
                return

            # 从右括号位置向前查找匹配的左括号
            brace_count = 1
            start_pos = end_pos
            while start_pos > 0 and brace_count > 0:
                start_pos -= 1
                if buffer[start_pos] == '{':
                    brace_count -= 1
                elif buffer[start_pos] == '}':
                    brace_count += 1

            if brace_count == 0:
                obj_str = buffer[start_pos:end_pos + 1]
                obj = json.loads(obj_str)
                parsed_objects.append(obj)

                # 发送解析结果
                await websocket_connection.send_json(obj)

        except (json.JSONDecodeError, ValueError) as e:
            # 记录解析错误但不中断流程
            print(f"JSON解析失败: {str(e)}")
            # 保留原始buffer继续积累数据

    # 创建正确的 SSL 上下文
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_NONE  # 禁用证书验证

    async with websockets.connect(ws_url, ssl=ssl_context) as ws:  # ✅ 使用正确 SSL 配置
        await ws.send(json.dumps(body))
        print("WebSocket 已连接")

        try:
            async for message in ws:
                try:
                    data = json.loads(message)
                    if data.get("code") != 0:
                        raise Exception(f"API Error: {data}")

                    content = data.get("content", "")
                    if content:
                        # 清理内容并处理缓冲区
                        cleaned = content.strip().strip('`').lstrip('json').strip()
                        print("收到内容片段:", cleaned)
                        buffer += cleaned
                        if '}' in cleaned:  # 只有包含右括号时才处理
                            await process_buffer()

                except Exception as e:
                    print("消息处理异常:", e)

        except websockets.exceptions.ConnectionClosed as e:
            print("WebSocket 连接已关闭:", e)
            try:
                parsed_data = json.loads(buffer)
                return parsed_data
            except json.JSONDecodeError as e:
                print("JSON 解析失败:", e)
                return None

        return parsed_objects  # ✅ 返回解析结果列表

from fastapi import WebSocket, WebSocketDisconnect
from urllib.parse import parse_qs, unquote

@router.websocket("/chat")
async def websocket_generate_interview_questions(websocket: WebSocket):
    await websocket.accept()


    interview_id = str(uuid4())

    # 验证JWT和获取 resume_id
    try:
        try:
            # 一次性接收包含 token 和 resume_id 的完整消息
            message = await websocket.receive_json()
            if not isinstance(message, dict) or "token" not in message or "resume_id" not in message:
                await websocket.send_json({"error": "Missing token or resume_id in initial message"})
                await websocket.close(code=4000)
                return

            token = message["token"]
            resume_id = message["resume_id"]

            # 使用 JWTUtil 解析 token
            jwt_util = JWTUtil()
            userid = jwt_util.extract_user_id(token)
            print("用户ID:", userid)

            # 发送 interview_id
            await websocket.send_json({"interview_id": interview_id})

        except HTTPException as e:
            await websocket.send_json({"error": e.detail})
            await websocket.close(code=4001)
            return

    except WebSocketDisconnect:
        print("客户端断开连接")
        return

    except Exception as e:
        await websocket.send_json({"error": str(e)})
        print("发生错误:", e)
        await websocket.close(code=4002)

    try:
        # 获取配置参数
        APPId = config['third_party']['chatdoc']['appid']
        APISecret = config['third_party']['chatdoc']['apisecret']
        OriginUrl = "wss://chatdoc.xfyun.cn/openapi/chat"
        curTime = str(int(time.time()))

        # 创建签名对象
        document_q_and_a = Document_Q_And_A(APPId, APISecret, curTime, OriginUrl)
        ws_url = document_q_and_a.get_url()

        # 从 Query 中解析参数
        query_string = websocket.scope["query_string"].decode()
        query_params = {}
        for part in query_string.split("&"):
            if "=" in part:
                key, value = part.split("=", 1)
                query_params[key] = unquote(value)
            else:
                query_params[part] = None

        fileids = query_params.get("fileids", "").split(",")
        job_position = query_params.get("job_position")

        # 从 Redis 查询 repoId
        type_param = query_params.get("type")
        repo_id = await redis_client.get(f"type:{type_param}:repoid")
        if isinstance(repo_id, bytes):
            repo_id = repo_id.decode("utf-8")

        # 构造请求体
        body = document_q_and_a.get_body(fileids, repo_id, job_position)

        # 发起外部 WebSocket 请求
        response = await send_websocket_request(
            ws_url,
            body,
            interview_id,
            websocket_connection=websocket
        )

        # 后续操作（如保存问题到数据库）
        from database import SessionLocal
        db = SessionLocal()
        from asyncio import create_task
        from service.resumes_service import save_resume_to_db

        async def run_background_tasks():
            REDIS_EXPIRE_TIME = 360000  # 1小时

            for question in response:
                question_key = f"file:{fileids[0]}:question:{question['id']}"
                await redis_client.hmset(
                    question_key,
                    {
                        "id": question["id"],
                        "context": question["context"],
                        "type": question["type"],
                        "score": question["score"]
                    }
                )
                # await redis_client.expire(question_key, REDIS_EXPIRE_TIME)

                # ✅ 新增：将 question_id 存入 Redis，以 interview_id 为 key 的集合中
                interview_question_set_key = f"interview:{interview_id}:questions"

            # 写入简历表F
            APPId = config['third_party']['chatdoc']['appid']
            APISecret = config['third_party']['chatdoc']['apisecret']
            await save_resume_to_db(db , userid , fileids[0], APPId, APISecret)
            # 写入面试表
            await create_interview_record(db, userid, job_position , interview_id , resume_id=resume_id)
            # 写入问题表
            await save_questions_to_db(db, userid, resume_id, response, job_position, interview_id)

        await run_background_tasks()

    except WebSocketDisconnect:
        print("客户端断开连接")

    except Exception as e:
        await websocket.send_json({"error": str(e)})
        print("发生错误:", e)
